﻿#include "InstanceMesh.h"

#include "MaterialSrc/InstanceMeshMaterial.h"

void FInstanceMesh::Draw(const FDrawArg& DrawArg) const
{
	Material->Use();

	const auto Shader = Material->GetShader();

	// 传递当前的 视图信息
	Shader->SetMat4("view", DrawArg.ViewMat);
	Shader->SetMat4("projection", DrawArg.ProjectionMat);

	if (OnSetShaderData)
	{
		OnSetShaderData(Shader);
	}

	// 绘制
	glBindVertexArray(VAO);

	glDrawElementsInstanced(GL_TRIANGLES, static_cast<int>(IndexArray.size()), GL_UNSIGNED_INT, nullptr,InstanceSize );

	glBindVertexArray(0);
}

void FInstanceMesh::SetInstanceTranform(const std::vector<glm::mat4>& InstanceTranformArr)
{
	InstanceSize = InstanceTranformArr.size();

	uint32_t VBO = 0;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, InstanceTranformArr.size()*sizeof(glm::mat4), InstanceTranformArr.data(), GL_STATIC_DRAW);  // NOLINT(bugprone-narrowing-conversions)

	glBindVertexArray(VAO);

	glEnableVertexAttribArray(3);
	glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
	glEnableVertexAttribArray(4);
	glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(1 * sizeof(glm::vec4)));
	glEnableVertexAttribArray(5);
	glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));
	glEnableVertexAttribArray(6);
	glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));
	
	glVertexAttribDivisor(3, 1);
	glVertexAttribDivisor(4, 1);
	glVertexAttribDivisor(5, 1);
	glVertexAttribDivisor(6, 1);

	glBindVertexArray(0);
}


std::shared_ptr<FMaterial> FInstanceModel::CreateMaterial(ETextureType Type) const
{
	return std::make_shared<FInstanceMeshMaterial>();
}

std::shared_ptr<FMesh> FInstanceModel::CreateMesh() const
{
	return std::make_shared<FInstanceMesh>();
}

void FInstanceModel::SetInstanceTranform(const std::vector<glm::mat4>& InstanceTranformArr)
{
	for (const auto & Mesh : MeshArray)
	{
		const auto InstanceMesh = std::static_pointer_cast<FInstanceMesh>(Mesh);
		InstanceMesh->SetInstanceTranform(InstanceTranformArr);
	}
}
